package com.lilanz.microservice.express.utils;

import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.itextpdf.text.BadElementException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.lilanz.microservice.express.entity.*;
import com.lilanz.microservice.express.utils.exception.MyException;
import com.lilanz.microservice.express.utils.util.JsonData;
import com.lilanz.microservice.express.utils.util.RamdomUtils;
import com.lilanz.microservice.express.utils.util.StringUtils;
import com.sf.csim.express.service.CallExpressServiceTools;
import org.dom4j.*;
import org.dom4j.io.SAXReader;

import javax.servlet.http.HttpServletResponse;


/**
 *  * 顺丰类
 *  * 
 *  * @author admin
 *  *
 *  
 */
public class ShunFengService {


    private static final String FILESUFFIX = "src/main/resources/static/";
    private String requrl;//远程顺丰接口
    private String checkWord;//校验码
    private String clientCode;//顾客码
    private String custId;//月结卡号
    private String codId;//代收货款的卡号
    //条形码二维码临时存放的路径
    private String imagePath;
    //pdf临时存放的路径
    private String pdfPath;

    public ShunFengService(Certificate certificate) {
        this.requrl = certificate.getReqUrl();
        this.checkWord = certificate.getCheckWord();
        this.clientCode = certificate.getClientCode();
        this.custId = certificate.getCustId();
        this.imagePath = StringUtils.getTemPath(certificate.getImagePath());
        this.pdfPath = StringUtils.getTemPath(certificate.getPdfPath());
        this.codId = certificate.getCodId();
    }


    /**
     * 打印电子面单
     *
     * @param printBeans
     * @return
     */
    public void sfExpressPrint(HttpServletResponse response, List<PrintBean> printBeans) {
        //模板的文件路径（因为就一个文件所以可以直接放在项目里无需单独创建一个文件夹）
        String templatePath = FILESUFFIX + "pdf/sf.pdf";
        //生成的新文件路径
        String newPDFPath = pdfPath + RamdomUtils.getRandomNumber() + ".pdf";
        PdfReader reader;
        ByteArrayOutputStream bos;
        PdfStamper stamper;
        PdfCopy copy = null;
        com.itextpdf.text.Document doc = null;
        FileOutputStream out = null;


        try {
            out = new FileOutputStream(newPDFPath);//输出流
            doc = new com.itextpdf.text.Document();
            copy = new PdfCopy(doc, out);
            doc.open();
            //避免导错jar包
            System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
            //中文字体,解决中文不能显示问题
            BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            SimpleDateFormat sf = new SimpleDateFormat("yyyy年MM月dd日  HH点mm分");

            //循环打印
            for (PrintBean printBean : printBeans) {
                //读取pdf模板  每次注入的信息都得读取一次模板 而最终输出的pdf就不用每次读取
                reader = new PdfReader(templatePath);
                bos = new ByteArrayOutputStream();
                stamper = new PdfStamper(reader, bos);
                AcroFields form = stamper.getAcroFields();
                //打印时间
                form.setFieldProperty("print_time", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                form.setField("print_time", "打印时间: " + sf.format(new Date()));
                //运单号
                form.setFieldProperty("mailno", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                form.setField("mailno", printBean.getMailno());

                //打印路由标签，若路由标签为空则打印目的地城市编码
                form.setFieldProperty("destRouteLabel", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                form.setField("destRouteLabel", StringUtils.isNotEmpty(printBean.getDestRouteLabel()) ? printBean.getDestRouteLabel() : printBean.getDestCityCode());
                //打印收件人姓名（不为空） 电话（不为空） 手机（可以为空）
                form.setFieldProperty("dMessage", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                form.setField("dMessage", printBean.getDContact() + "  " + printBean.getDTel() + (StringUtils.isNotEmpty(printBean.getDMobile()) ? "  " + printBean.getDMobile() : ""));
                //打印收件人公司名称 可以为空
                form.setFieldProperty("dCompany", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                form.setField("dCompany", (StringUtils.isNotEmpty(printBean.getDCompany()) ? printBean.getDCompany() : ""));
                //打印省市区 均不能为空
                form.setFieldProperty("dPCC", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                form.setField("dPCC", (StringUtils.isNotEmpty(printBean.getDProvince()) ? printBean.getDProvince() : "") + " " + printBean.getDCity() + " " + printBean.getDCounty());
                //收件人地址 不能为空
                form.setFieldProperty("dAddress", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                form.setField("dAddress", printBean.getDAddress());
                //codingMapping
                form.setFieldProperty("codingMapping", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                form.setField("codingMapping", printBean.getCodingMapping());
                //sourceTransferCode
                form.setFieldProperty("sourceTransferCode", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                form.setField("sourceTransferCode", printBean.getSourceTransferCode());

                //付款方式
                form.setFieldProperty("payment", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                form.setField("payment", "寄付月结");


                //打印寄件人姓名（不为空） 电话（不为空） 手机（可以为空）
                form.setFieldProperty("jMessage", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                form.setField("jMessage", printBean.getJContact() + "  " + printBean.getJTel() + (StringUtils.isNotEmpty(printBean.getJMobile()) ? "  " + printBean.getJMobile() : ""));
                //打印寄件人公司名称 可以为空
                form.setFieldProperty("jCompany", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                form.setField("jCompany", (StringUtils.isNotEmpty(printBean.getJCompany()) ? printBean.getJCompany() : ""));
                //打印省市区 均不能为空
                form.setFieldProperty("jPCC", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                form.setField("jPCC", (StringUtils.isNotEmpty(printBean.getJProvince()) ? printBean.getJProvince() : "") + " " + printBean.getJCity() + " " + printBean.getJCounty());
                //寄件人地址 不能为空
                form.setFieldProperty("jAddress", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                form.setField("jAddress", printBean.getJAddress());
                //货物名称
                form.setFieldProperty("good", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                form.setField("good", printBean.getName());
                //备注
                form.setFieldProperty("remark", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                form.setField("remark", (StringUtils.isNotEmpty(printBean.getRemark()) ? printBean.getRemark() : "") + "  " + (StringUtils.isNotEmpty(printBean.getReturnMailno()) ? "签回单: " + printBean.getReturnMailno() : ""));


                //若有增值服务代收货款
                if (StringUtils.isNotEmpty(printBean.getCod())) {
                    //cod图片打印
                    codImage(stamper, form);
                    //付款的金额
                    form.setFieldProperty("cod", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form.setField("cod", "#金额#:  " + printBean.getCod() + "元");

                    form.setFieldProperty("service", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form.setField("service", "COD");
                }

                //二维码的生成
                twoDimensionCodeImage(stamper, form, printBean.getTwoDimensionCode());
                //abFlag
                if (StringUtils.isNotEmpty(printBean.getAbFlag())) {
                    //cod图片打印
                    abImage(stamper, form, printBean.getAbFlag());

                }

                //根据运单号生成条形码
                barCodeImage(stamper, form, printBean.getMailno());
                //生成proCode图片
                if (StringUtils.isNotEmpty(printBean.getProCode()))
                    proCodeImage(stamper, form, printBean.getProCode());
                stamper.close();
                PdfImportedPage importPage = copy.getImportedPage(
                        new PdfReader(bos.toByteArray()), 1);
                copy.addPage(importPage);

                //有签回单的情况
                if (StringUtils.isNotEmpty(printBean.getReturnMailno())) {
                    //读取pdf模板  每次注入的信息都得读取一次模板 而最终输出的pdf就不用每次读取
                    reader = new PdfReader(templatePath);
                    bos = new ByteArrayOutputStream();
                    stamper = new PdfStamper(reader, bos);
                    AcroFields form1 = stamper.getAcroFields();
                    //打印时间
                    form1.setFieldProperty("print_time", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("print_time", "打印时间: " + sf.format(new Date()));
                    //运单号
                    form1.setFieldProperty("mailno", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("mailno", printBean.getReturnMailno());
                    //打印路由标签，若路由标签为空则打印目的地城市编码
                    form1.setFieldProperty("destRouteLabel", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("destRouteLabel", StringUtils.isNotEmpty(printBean.getReturnDestRouteLabel()) ? printBean.getReturnDestRouteLabel() : printBean.getReturnDestCityCode());
                    //打印收件人姓名（不为空） 电话（不为空） 手机（可以为空）
                    form1.setFieldProperty("dMessage", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("dMessage", printBean.getJContact() + "  " + printBean.getJTel() + (StringUtils.isNotEmpty(printBean.getJMobile()) ? "  " + printBean.getJMobile() : ""));
                    //打印收件人公司名称 可以为空
                    form1.setFieldProperty("dCompany", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("dCompany", (StringUtils.isNotEmpty(printBean.getJCompany()) ? printBean.getJCompany() : ""));
                    //打印省市区 均不能为空
                    form1.setFieldProperty("dPCC", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("dPCC", (StringUtils.isNotEmpty(printBean.getJProvince()) ? printBean.getJProvince() : "") + " " + printBean.getJCity() + " " + printBean.getJCounty());
                    //收件人地址 不能为空
                    form1.setFieldProperty("dAddress", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("dAddress", printBean.getJAddress());
                    //codingMapping
                    form1.setFieldProperty("codingMapping", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("codingMapping", printBean.getReturnCodingMapping());
                    //sourceTransferCode
                    form1.setFieldProperty("sourceTransferCode", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("sourceTransferCode", printBean.getReturnSourceTransferCode());

                    //付款方式
                    form1.setFieldProperty("payment", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("payment", "到付");


                    //打印寄件人姓名（不为空） 电话（不为空） 手机（可以为空）
                    form1.setFieldProperty("jMessage", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("jMessage", printBean.getDContact() + "  " + printBean.getDTel() + (StringUtils.isNotEmpty(printBean.getDMobile()) ? "  " + printBean.getDMobile() : ""));
                    //打印寄件人公司名称 可以为空
                    form1.setFieldProperty("jCompany", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("jCompany", (StringUtils.isNotEmpty(printBean.getDCompany()) ? printBean.getDCompany() : ""));
                    //打印省市区 均不能为空
                    form1.setFieldProperty("jPCC", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("jPCC", (StringUtils.isNotEmpty(printBean.getDProvince()) ? printBean.getDProvince() : "") + " " + printBean.getDCity() + " " + printBean.getDCounty());
                    //寄件人地址 不能为空
                    form1.setFieldProperty("jAddress", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("jAddress", printBean.getDAddress());
                    //货物名称
                    form1.setFieldProperty("good", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("good", "签回单");
                    //备注
                    form1.setFieldProperty("remark", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("remark", "主单号： " + printBean.getMailno());


                    form1.setFieldProperty("service", "textfont", bfChinese, null);//为每一个表单属性设置中文字体
                    form1.setField("service", "POD");


                    //二维码的生成
                    twoDimensionCodeImage(stamper, form1, printBean.getReturnTwoDimensionCode());


                    //abFlag
                    if (StringUtils.isNotEmpty(printBean.getReturnAbFlag())) {
                        //cod图片打印
                        abImage(stamper, form1, printBean.getReturnAbFlag());

                    }
                    //在签回单上生成pod标识
                    podImage(stamper, form1);
                    //根据运单号生成条形码
                    barCodeImage(stamper, form1, printBean.getReturnMailno());
                    //生成proCode图片
                    if (StringUtils.isNotEmpty(printBean.getReturnProCode()))
                        proCodeImage(stamper, form1, printBean.getReturnProCode());
                    stamper.close();
                    PdfImportedPage importPage1 = copy.getImportedPage(
                            new PdfReader(bos.toByteArray()), 1);
                    copy.addPage(importPage1);
                }


            }


            try {
                copy.close();
                doc.close();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
                throw new MyException(" 出错了原因为: " + e.getMessage());
            }

            //下载pdf
            downloadFile(response, newPDFPath);
        } catch (IOException | DocumentException e) {
            e.printStackTrace();
            throw new MyException(" 出错了原因为: " + e.getMessage());
        } catch (com.itextpdf.text.DocumentException e) {
            e.printStackTrace();
            throw new MyException("   出错了原因为: " + e.getMessage());
        }
    }


    /**
     * pdf下载
     */

    private void downloadFile(HttpServletResponse response, String pdfPath) {
        File file = new File(pdfPath);
        if (file.exists() && file.isFile()) {
            response.setHeader("content-Type", "application/pdf");
            try {
                response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(pdfPath.substring(pdfPath.lastIndexOf("/") + 1), "UTF-8"));// 设置文件名
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                throw new MyException("   出错了原因为: " + e.getMessage());
            }
            byte[] buffer = new byte[1024];
            FileInputStream fis = null;
            BufferedInputStream bis = null;
            try {
                fis = new FileInputStream(file);
                bis = new BufferedInputStream(fis);
                OutputStream os = response.getOutputStream();
                int i = bis.read(buffer);
                while (i != -1) {
                    os.write(buffer, 0, i);
                    i = bis.read(buffer);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (bis != null) {
                    try {
                        bis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }


    /**
     * 请求顺丰接口汇总 ：下单
     *
     * @param expresses
     * @return
     */
    public Object sfExpressCommit(List<ShunFengExpress> expresses) {
        ArrayList<ResultCommit> results = new ArrayList<>();
        //遍历每个订单号进行分批上传
        for (ShunFengExpress express : expresses) {
            //生成下订单相关的xml
            String xml = commitOrderXml(express);
            ResultCommit resultExpress;
            try {
                resultExpress = getCommitOrderResult(xml, express.getOrderId());
            } catch (Exception e) {
                e.printStackTrace();
                //错误抛出去
                throw new MyException("错误发生：错误信息" + e.getMessage());
            }
            //获取每个订单上传的结果放回list中
            results.add(resultExpress);
        }
        return JsonData.buildSuccess(results);
    }


    /**
     * 请求顺丰接口汇总 ：取消订单
     */
    public Object sfExpressCancel(String orderId) {
        //生成取消订单相关的xml
        String xml = cancelOrderXml(orderId);
        Document doc;
        try {
            //连接顺丰公司传送xml并返回xml报文
            doc = getResultByConnectSF(xml);
        } catch (DocumentException | UnsupportedEncodingException e) {
            e.printStackTrace();
            //抛出错误给前端
            throw new MyException("错误发生：错误信息" + e.getMessage());
        }
        Node node = doc.selectSingleNode("//Response/Head");
        String res = node.getText();
        ResultCommit result = new ResultCommit();
        if ("ERR".equals(res)) {//错误
            node = doc.selectSingleNode("//Response/ERROR");
            res = node.getText();
            result.setCode(500)
                    .setOrderId(orderId)
                    .setMessage(res);
            return JsonData.buildSuccess(result);
        }
        //正确情况下
        node = doc.selectSingleNode("//Response/Body");
        Element element = (Element) node;
        Element node0 = (Element) element.node(0);
        List<Attribute> attributes = node0.attributes();
        for (Attribute attribute : attributes) {
            //遍历出来的xml结点属性是mailno提取其值：运单号
            if (attribute.getName().equals("res_status")) {
                String value = attribute.getValue();
                //2代表取消成功    1代表确认订单业务  客户订单号与顺丰运单不匹配的情况(与本次业务无关)双重检验安全点
                if (value.equals("2")) {
                    result.setCode(200)
                            .setOrderId(orderId)
                            .setMessage("取消成功");
                    return JsonData.buildSuccess(result);
                }
            }
        }

        return JsonData.buildError("未知原因发生错误,一般是顺丰公司那边的错误或者顺丰公司修改了xml报文格式，请重新查看新文档并且修改本次代码");
    }


    /**
     * 请求顺丰接口汇总 ：订单查看(根据订单号查看货运号)
     */
    public ResultCommit sfExpressCheck(String orderId, String message) {
        //生成查看订单相关的xml
        String xml = checkOrderXml(orderId);
        Document doc;
        try {
            //连接顺丰公司传送xml并返回xml报文
            doc = getResultByConnectSF(xml);
        } catch (DocumentException | UnsupportedEncodingException e) {
            e.printStackTrace();
            //抛出错误给前端
            throw new MyException("错误发生：错误信息" + e.getMessage());
        }
        Node node = doc.selectSingleNode("//Response/Head");
        String res = node.getText();
        ResultCommit result = new ResultCommit();
        if ("ERR".equals(res)) {//错误
            node = doc.selectSingleNode("//Response/ERROR");
            res = node.getText();
            result.setCode(500)
                    .setOrderId(orderId)
                    .setMessage(res);
            return result;
        }
        //正确情况下
        result.setCode(200);
        result.setMessage(message);
        //返回单次正确的信息
        node = doc.selectSingleNode("//Response/Body");
        Element element = (Element) node;
        //对象地址符引用
        treeWalkCommit(result, element, 0);
        return result;


    }


    /**
     * 请求顺丰接口，处理xml格式的数据
     */
    private ResultCommit getCommitOrderResult(String xml, String orderId) throws Exception {
        //连接顺丰公司传送xml并返回xml报文
        Document doc = getResultByConnectSF(xml);
        //解析xml
        Node node = doc.selectSingleNode("//Response/Head");
        String res = node.getText();
        ResultCommit result = new ResultCommit();
        //返回单次错误信息
        if ("ERR".equals(res)) {
            node = doc.selectSingleNode("//Response/ERROR");
            res = node.getText();
            if (res.equals("重复下单")) {
                //重复下单就找出这个订单号的货运单
                result = sfExpressCheck(orderId, "此单重复下单,已帮你找出下面的参数了");
            } else {
                result.setCode(500)
                        .setOrderId(orderId)
                        .setMessage(res);
            }
            return result;
        }
        //返回单次正确的信息
        node = doc.selectSingleNode("//Response/Body");
        Element element = (Element) node;
        result.setCode(200);
        result.setMessage("下单成功");

        //对象地址符引用
        treeWalkCommit(result, element, 0);
        return result;
    }

    //递归
    private void treeWalkCommit(ResultCommit result, Element element, int count) {
        if (count >= 10) {
            return;
        }
        //虽然这个递归正常获取顺丰报文不会死循环(最多3次循环) 还是留一手避免收到无限大的报文死循环
        for (int i = 0, size = element.nodeCount(); i < size; i++) {
            Element node = (Element) element.node(i);
            List<Attribute> list = node.attributes();
            for (Attribute attribute : list) {
                //因为顺丰返回过来的签回单和主运单的参数名都是一样的
                // 所以得从递归的次数来判断哪些是主运单的参数，哪些是签回单的参数
                //经测试当count=3的时候会遍历到签回单的参数,所有count=0,1,2里面的参数都是主运单的 count=3为签回单的

                //遍历出来的xml结点属性是mailno提取其值：运单号或签回单  其他类似
                if (attribute.getName().equals("waybillNo")) {
                    if (count <= 2)
                        result.setMailno(attribute.getValue());
                    else
                        result.setReturnMailno(attribute.getValue());
                }


                if (attribute.getName().equals("orderid")) {//订单号只有一个
                    result.setOrderId(attribute.getValue());
                }


                if (attribute.getName().equals("origincode")) {//一个
                    if (count <= 2)
                        result.setOrigincode(attribute.getValue());
                }


                if (attribute.getName().equals("destcode")) {//一个
                    if (count <= 2)
                        result.setDestcode(attribute.getValue());
                }


                if (attribute.getName().equals("sourceTransferCode")) {
                    if (count <= 2)
                        result.setSourceTransferCode(attribute.getValue());
                    else
                        result.setReturnSourceTransferCode(attribute.getValue());
                }

                if (attribute.getName().equals("abFlag")) {
                    if (count <= 2)
                        result.setAbFlag(attribute.getValue());
                    else
                        result.setReturnAbFlag(attribute.getValue());
                }

                if (attribute.getName().equals("destRouteLabel")) {
                    if (count <= 2)
                        result.setDestRouteLabel(attribute.getValue());
                    else
                        result.setReturnDestRouteLabel(attribute.getValue());
                }

                if (attribute.getName().equals("destCityCode")) {
                    if (count <= 2)
                        result.setDestCityCode(attribute.getValue());
                    else
                        result.setReturnDestCityCode(attribute.getValue());
                }


                if (attribute.getName().equals("destTeamCode")) {
                    if (count <= 2)
                        result.setDestTeamCode(attribute.getValue());
                    else
                        result.setReturnDestTeamCode(attribute.getValue());
                }


                if (attribute.getName().equals("printIcon")) {
                    if (count <= 2)
                        result.setPrintIcon(attribute.getValue());
                    else
                        result.setReturnPrintIcon(attribute.getValue());
                }

                if (attribute.getName().equals("proCode")) {
                    if (count <= 2)
                        result.setProCode(attribute.getValue());
                    else
                        result.setReturnProCode(attribute.getValue());
                }
                if (attribute.getName().equals("xbFlag")) {
                    if (count <= 2)
                        result.setXbFlag(attribute.getValue());
                    else
                        result.setReturnXbFlag(attribute.getValue());
                }
                if (attribute.getName().equals("codingMapping")) {
                    if (count <= 2)
                        result.setCodingMapping(attribute.getValue());
                    else
                        result.setReturnCodingMapping(attribute.getValue());
                }
                if (attribute.getName().equals("twoDimensionCode")) {
                    if (count <= 2)
                        result.setTwoDimensionCode(attribute.getValue());
                    else
                        result.setReturnTwoDimensionCode(attribute.getValue());
                }
            }

            treeWalkCommit(result, (Element) node, ++count);
        }

    }


    /**
     * 查看此运单号的路由信息
     */
    public Object sfExpressRoute(String mailno) {
        String xml = routeMessageXml(mailno);
        Document doc;
        try {
            doc = getResultByConnectSF(xml);
        } catch (DocumentException | UnsupportedEncodingException e) {
            e.printStackTrace();
            throw new MyException("错误发生：错误信息" + e.getMessage());
        }
        //解析xml
        Node node = doc.selectSingleNode("//Response/Head");
        String res = node.getText();
        ResultRoute result = new ResultRoute();
        //返回单次错误信息
        if ("ERR".equals(res)) {
            node = doc.selectSingleNode("//Response/ERROR");
            res = node.getText();
            result.setCode(500)
                    .setMailno(mailno)
                    .setMessage(res);
            return result;
        }
        //返回单次正确的信息
        node = doc.selectSingleNode("//Response/Body");
        Element element = (Element) node;
        result.setCode(200);
        result.setMessage("查询运单路线成功");
        //对象地址符引用
        result.setRouteMessgae(treeWalkRoute(element, 0));
        return result;
    }

    //递归
    private JSONObject treeWalkRoute(Element element, int count) {
        if (count >= 20) {//避免死循环，只要顺丰传递我的报文格式正确就不会死循环 预防一下
            return null;
        }
        JSONObject obj = new JSONObject();
        List<Attribute> list = element.attributes();
        for (Attribute att : list) {
            obj.put(att.getName(), att.getValue());
        }
        Map<String, List<JSONObject>> subNodes = new HashMap();
        for (int i = 0, size = element.nodeCount(); i < size; i++) {
            Node node = element.node(i);
            String name = node.getName();
            Element el = (Element) node;

            if (node instanceof Element) {
                JSONObject newNode = treeWalkRoute(el, ++count);
                List<JSONObject> _subNodes = subNodes.get(name);
                if (_subNodes == null) {
                    _subNodes = new ArrayList();
                }
                _subNodes.add(newNode);
            } else {
                obj.put(name, node.getText());
            }
        }
        for (String key : subNodes.keySet()) {
            List<JSONObject> _subNodes = subNodes.get(key);
            if (_subNodes.size() > 1) {
                JSONArray jsonArray = new JSONArray();
                for (JSONObject o : _subNodes) {
                    jsonArray.add(o);
                }
                obj.put(key, jsonArray);
            } else {
                obj.put(key, _subNodes.get(0));
            }
        }

        return obj;

    }


    /**
     * 连接顺丰公司传送xml并返回xml报文
     */
    private Document getResultByConnectSF(String xml) throws DocumentException, UnsupportedEncodingException {
        String resultByNet = CallExpressServiceTools.callSfExpressServiceByCSIM(requrl, xml, clientCode, checkWord);
        if (!StringUtils.isNotEmpty(resultByNet)) {
            throw new MyException("顺丰接口失败信息返回: 顺丰传递过来的信息是空信息");
        }
//        System.out.println(resultByNet);
        // 对返回的xml数据进行编码处理
        SAXReader reader = new SAXReader();
        return reader.read(new ByteArrayInputStream(resultByNet.getBytes("UTF-8")));
    }


    /**
     * 下订单xml报文
     */
    private String commitOrderXml(ShunFengExpress express) {
        StringBuilder sb = new StringBuilder();
        sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
        sb.append("<Request service=\"OrderService\" lang=\"zh-CN\">");
        sb.append("<Head>").append(clientCode).append("</Head>"); //注意这里的head
        sb.append("<Body>");
        sb.append("<Order orderid=\"").append(express.getOrderId()).append("\" ");
        //普通快递 返回运单
        sb.append("express_type='1' is_gen_bill_no='1' ");
        sb.append("j_province='").append(express.getJProvince()).append("' ");
        sb.append("j_city='").append(express.getJCity()).append("' ");
        if (StringUtils.isNotEmpty(express.getJCompany()))
            sb.append("j_company='").append(express.getJCompany()).append("' ");
        sb.append("j_contact='").append(express.getJContact()).append("' ");
        if (StringUtils.isNotEmpty(express.getJTel()))
            sb.append("j_tel='").append(express.getJTel()).append("' ");
        if (StringUtils.isNotEmpty(express.getJMobile()))
            sb.append("j_mobile='").append(express.getJMobile()).append("' ");
        sb.append("j_county='").append(express.getJCounty()).append("' ");
        sb.append("j_address='").append(express.getJAddress()).append("' ");
        sb.append("d_province='").append(express.getDProvince()).append("' ");
        sb.append("d_city='").append(express.getDCity()).append("' ");
        if (StringUtils.isNotEmpty(express.getDCompany()))
            sb.append("d_company='").append(express.getDCompany()).append("' ");
        sb.append("d_contact='").append(express.getDContact()).append("' ");
        if (StringUtils.isNotEmpty(express.getDTel()))
            sb.append("d_tel='").append(express.getDTel()).append("' ");

        if (StringUtils.isNotEmpty(express.getDMobile()))
            sb.append("d_mobile='").append(express.getDMobile()).append("' ");

        sb.append("d_county='").append(express.getDCounty()).append("' ");
        sb.append("d_address='").append(express.getDAddress()).append("' ");
        //月结卡号
        sb.append("custid='").append(custId).append("' ");
        //快递备注
        if (StringUtils.isNotEmpty(express.getRemark()))
            sb.append("remark='").append(express.getRemark()).append("' ");
        //是否返回签回单  1为返回  其余值不返回
        if (StringUtils.isNotEmpty(express.getNeedReturnTrackingNo())) {
            if (express.getNeedReturnTrackingNo().equals("1")) {
                sb.append("need_return_tracking_no='").append(1).append("' ");
                sb.append("routelabelForReturn='").append(1).append("' ");
                sb.append("routelabelService ='").append(1).append("' ");
            }

        }
        //parcel_quantity包裹数量1 pay_method 1寄方付 2到方付钱 3第三方付钱
        sb.append("parcel_quantity='1' pay_method='1' > ");
        //货物名称
        if (StringUtils.isNotEmpty(express.getName()))
            sb.append("<Cargo \n" + "\tname='").append(express.getName()).append("' \n").append("\t/> ");
        //待收货款
        if (StringUtils.isNotEmpty(express.getCod()))
            sb.append("<AddedService name=\"COD\" value='").append(express.getCod()).append("' value1='").append(codId).append("'").append(" />");
        //保价
        if (StringUtils.isNotEmpty(express.getInsure()))
            sb.append("<AddedService name=\"INSURE\" value=\"").append(express.getInsure()).append("\"/>");
        sb.append("</Order></Body></Request>");
//        System.out.println(sb.toString());
        return sb.toString();
    }


    private void twoDimensionCodeImage(PdfStamper stamper, AcroFields form, String twoDimensionCode) throws IOException, DocumentException {
        String path = imagePath + RamdomUtils.getRandomNumber() + ".png";
        boolean flag = StringUtils.twoDimensionCode(twoDimensionCode, path);
        if (!flag) {
            throw new MyException("生成二维码失败");
        }
        int pageNo = form.getFieldPositions("twoDimensionCode").get(0).page;
        Rectangle signRect = form.getFieldPositions("twoDimensionCode").get(0).position;
        float x = signRect.getLeft(0);
        float y = signRect.getBottom(0);
        //读取临时图片放入pdf中
        readImage(stamper, pageNo, signRect, x, y, path);
    }


    private void podImage(PdfStamper stamper, AcroFields form) throws IOException, DocumentException {
        int pageNo = form.getFieldPositions("pod").get(0).page;
        Rectangle signRect = form.getFieldPositions("pod").get(0).position;
        float x = signRect.getLeft(0);
        float y = signRect.getBottom(10);
        readImage(stamper, pageNo, signRect, x, y, FILESUFFIX + "image/" + "pod.png");
    }

    private void abImage(PdfStamper stamper, AcroFields form, String abFlag) throws IOException, DocumentException {
        int pageNo = form.getFieldPositions("abFlag").get(0).page;
        Rectangle signRect = form.getFieldPositions("abFlag").get(0).position;
        float x = signRect.getLeft(0);
        float y = signRect.getBottom(10);
        if (abFlag.equals("B"))
            abFlag = "B";
        else abFlag = "A";
        readImage(stamper, pageNo, signRect, x, y, FILESUFFIX + "image/" + abFlag + ".jpg");
    }

    private void codImage(PdfStamper stamper, AcroFields form) throws IOException, DocumentException {
        int pageNo = form.getFieldPositions("codImage").get(0).page;
        Rectangle signRect = form.getFieldPositions("codImage").get(0).position;
        float x = signRect.getLeft(10);
        float y = signRect.getBottom(0);
        readImage(stamper, pageNo, signRect, x, y, FILESUFFIX + "image/" + "cod.png");
    }

    private void proCodeImage(PdfStamper stamper, AcroFields form, String proCode) throws IOException, DocumentException {
        int pageNo = form.getFieldPositions("pro_code").get(0).page;
        Rectangle signRect = form.getFieldPositions("pro_code").get(0).position;
        float x = signRect.getLeft(10);
        float y = signRect.getBottom(0);
        switch (proCode) {
            case "T1":
                break;
            case "T6":
                break;
            case "T8":
                break;
            case "T9":
                break;
            default:
                proCode = "T4";
                break;
        }
        readImage(stamper, pageNo, signRect, x, y, FILESUFFIX + "image/" + proCode + ".png");
    }

    private void barCodeImage(PdfStamper stamper, AcroFields form, String mailno) throws IOException, DocumentException {
        int pageNo = form.getFieldPositions("barcode").get(0).page;
        Rectangle signRect = form.getFieldPositions("barcode").get(0).position;
        float x;
        if (mailno.length() <= 12)
            x = signRect.getLeft(16);
        else
            x = signRect.getLeft(5);
        float y = signRect.getBottom(0);
        //临时图片路径
        String path = imagePath + RamdomUtils.getRandomNumber() + ".png";
        //生成条形码放到临时图片路径
        StringUtils.barCode(mailno, path);
        //读取临时图片放入pdf中
        readImage(stamper, pageNo, signRect, x, y, path);
    }

    private void readImage(PdfStamper stamper, int pageNo, Rectangle signRect, float x, float y, String path) throws DocumentException, IOException {
        // 读图片
        Image image = null;
        try {
            image = Image.getInstance(path);
        } catch (BadElementException e) {
            e.printStackTrace();
        }

        // 获取操作的页面
        PdfContentByte under = stamper.getOverContent(pageNo);
        // 根据域的大小缩放图片
        assert image != null;
        image.scaleToFit(signRect.getWidth(), signRect.getHeight());
        // 添加图片
        image.setAbsolutePosition(x, y);
        try {
            under.addImage(image);
        } catch (com.itextpdf.text.DocumentException e) {
            e.printStackTrace();
        }
    }


    /**
     * 取消订单xml报文
     */
    private String cancelOrderXml(String orderId) {
        return "<Request service=\"OrderConfirmService\" lang=\"zh-CN\">\n" +
                "<Head>" + clientCode + "</Head>\n" +
                "<Body>\n" +
                "<OrderConfirm\n" +
                "orderid=\"" + orderId + "\"\n" +
                "dealtype=\"2\">\n" + //2代表取消订单 1代表确认订单
                "</OrderConfirm>\n" +
                "</Body>\n" +
                "</Request>";
    }

    /**
     * 查看订单xml报文
     */
    private String checkOrderXml(String orderId) {
        //编译器会自动优化下面字符串的拼接 无需new StringBulider()
        return "<Request service=\"OrderSearchService\"  lang=\"zh-CN\">\n" +
                "<Head>" + clientCode + "</Head>\n" +
                "<Body>\n" +
                "<OrderSearch orderid=\"" + orderId + "\"/>\n" +
                "</Body>\n" +
                "</Request>";
    }


    /**
     * 订单路由轨迹信息
     */
    private String routeMessageXml(String mailno) {
        return "<Request service='RouteService' lang='zh-CN'>\n" +
                "<Head>" + clientCode + "</Head>\n" +
                "<Body>\n" +
                "<RouteRequest\n" +
                "tracking_type='1'\n" + //1为根据运单号查询 ，2 为根据订单号查询
                "method_type='1'\n" +  //1为标准的路由信息
                "tracking_number=\"" + mailno + "\"/>\n" +
                "</Body>\n" +
                "</Request>";
    }


}
